package server;

import interfaces.Master;
import interfaces.Peer;
import java.net.InetAddress;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import Log.*;


// Usage  : Driver [rmi_registry_IP] [rmi_registry_port]

public class Driver {

	public static void main(String[] args) {
		int rmiRegistryPort = 2009;
		String rmiRegistryIP = "127.0.0.1";
		
		// parse command line arguments
		if (args.length > 2) {
			usage();
			return;
		} else if (args.length == 2) {
			rmiRegistryPort = Integer.parseInt(args[1]);
    	}
		if (args.length >= 1) {
			rmiRegistryIP = args[0];
    	}
		
		Registry registry;
		
		try {
			registry = LocateRegistry.getRegistry(rmiRegistryIP, rmiRegistryPort);
		} catch (RemoteException e) {
			Log.log(MessageType.Error, "Cannot connect to RMI registry.");
			throw new RuntimeException(e.getMessage());
		}
				
		PrimePeer localPeer = createLocalPeer(registry);
		
		PrimeWorker worker = new PrimeWorker();
		
		do {
			
			try {
				worker.setMaster((Master) registry.lookup("master"));
				worker.compute();
			} catch (NotBoundException e) {
				Log.log(MessageType.Election, "Master stub not bounded. Start an election.");
				
				localPeer.election();
			} catch (RemoteException e) {
				Log.log(MessageType.Election, "Master has crashed. Start an election.");
				
				localPeer.election();
			}
			
			Log.log(MessageType.Election, "Election is over.");
		// Check if the master is myself.
		// If it isn't, continue working.
		} while (!localPeer.IAmMaster());
		
		// If it is, do nothing.
		Log.log(MessageType.Election, "I am the master!");
	}

	private static PrimePeer createLocalPeer(Registry registry) {
		
		if (System.getSecurityManager() == null) {
            System.setSecurityManager(new SecurityManager());
        }
		
		PrimePeer peer = null;
		try {
			String name = "peer:" + InetAddress.getLocalHost().toString();
			
			peer = new PrimePeer(registry, name);
			Peer peerStub = (Peer) UnicastRemoteObject.exportObject(peer, 0);
			
			registry.bind(name, peerStub);
					
			Log.log(MessageType.Election, "Register " + name + " succeeds.");
		} catch (Exception e) {
			Log.log(MessageType.Error, "Failed to create the election Peer.");
			throw new RuntimeException(e.getMessage());
		}
		
		return peer;
	}

	private static void usage() {
		System.out.println("Usage: Driver [rmi registry IP] [rmi registry port]");
	}

}
